package com.aqs;

import java.util.TreeMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Logger;

/**
 * 手写AQS
 */
public class MysLockAQS {

    /**
     * 是否加锁标识，锁状态(0:锁存在；1: 锁已给线程)
     */
    private AtomicInteger lockState = new AtomicInteger(0);

    /**
     * 获取锁的对象
     */
    private Thread thread = null;

    /**
     * 锁类型(true: 公平锁；false: 非公平锁)
     */
    private boolean lockType = false;

    /**
     * 重入锁次数
     */
    private Integer state = 0;

    /**
     * 没有获取锁得线程，保存到该链表
     */
    private ConcurrentLinkedDeque<Thread> concurrentLinkedDeque = new ConcurrentLinkedDeque<Thread>();


    public MysLockAQS(){

    }

    public MysLockAQS(boolean lockType){
        this.lockType = lockType;
    }

    /**
     * 加锁
     * @return
     */
    public boolean lock(){

        // 这里死循环指的是，被阻塞得线程被唤醒后要不断地重试
        for (;;){
            // 通过CAS尝试加锁
            if(acquire()){
                // 加锁成功，thread赋予当前线程
                thread = Thread.currentThread();
                // state赋值1，表示加锁1次
                state = 1;
                // 加锁成功，直接退出循环
                return true;
            }else{
                // 加锁失败，判断是不是当前线程
                if(thread == Thread.currentThread()){
                    // 是当前线程，则依然放行，并且state+1
                    state++;
                    return true;
                }
            }

            // 加锁失败，把该线程加入链表保存
            concurrentLinkedDeque.add(Thread.currentThread());
            // 阻塞当前线程，被unPark唤醒后，继续从这里执行，即进入下一次循环
            LockSupport.park();
        }

    }

    /**
     * 解锁
     * @return
     */
    public boolean unLock(){
        // 判断当前是否有线程拿到锁
        if(thread == null){
            return false;
        }
        // 判断如果是当前线程
        if(thread == Thread.currentThread()){
            // 判断state是否为1
            if(state > 1){
                // 大于1，则说明有重入锁，需要state - 1, 但不能释放锁
                state--;
                return true;
            }
            // CAS执行解锁
            if(compareAndSetState(1, 0)){
                // 解锁成功，判断是公平锁还是非公平锁
                if(lockType){
                    // 公平锁，则唤醒链表中第一个线程
                    Thread first = concurrentLinkedDeque.pollFirst();
                    // 唤醒该线程
                    LockSupport.unpark(first);
                }else{
                    // 非公平锁，循环唤醒链表所有线程，让他们自己抢占去
                    for(;;){
                        if(concurrentLinkedDeque.size() == 0){
                            System.out.println("队列已空");
                           break;
                        }
                        // 公平锁，则唤醒链表中第一个线程
                        Thread first = concurrentLinkedDeque.pollFirst();
                        // 唤醒该线程
                        LockSupport.unpark(first);
                    }

                }
            }
        }

        return false;
    }

    private boolean acquire(){
        if(compareAndSetState(0, 1)){
            return true;
        }
        return false;
    }
    /**
     * CAS
     * @param expect   期待原值
     * @param update   更改新值
     * @return
     */
    private boolean compareAndSetState(int expect, int update){
        return lockState.compareAndSet(expect, update);
    }

}
